Skip to content

[Cranelift] add simplification rules#12948

Merged
cfallin merged 1 commit intobytecodealliance:mainfrom
myunbin:add-rules-040326
Apr 6, 2026
Merged

[Cranelift] add simplification rules#12948
cfallin merged 1 commit intobytecodealliance:mainfrom
myunbin:add-rules-040326

Conversation

@myunbin
Copy link
Copy Markdown
Contributor

@myunbin myunbin commented Apr 3, 2026

This PR adds several simplification rules:

arithmetic.isle

  • (x - y) == x --> y == 0
  • (x + y) == y --> x == 0
  • -x == -y --> x == y
  • -((-y) * x) --> x * y
  • ireduce(xext(a) + xext(b)) --> a + b
  • ireduce(xext(a) - xext(b)) --> a - b
  • max(x, y) >= x --> 1
  • x >= min(x, y) --> 1

bitops.isle

  • (x & ~y) == ~y --> (x | y) == -1
  • x >= (x & y) --> 1 and its dual

@myunbin myunbin requested a review from a team as a code owner April 3, 2026 08:28
@myunbin myunbin requested review from cfallin and removed request for a team April 3, 2026 08:28
@github-actions github-actions bot added cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language labels Apr 3, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 3, 2026

Subscribe to Label Action

cc @cfallin, @fitzgen

Details This issue or pull request has been labeled: "cranelift", "isle"

Thus the following users have been cc'd because of the following labels:

  • cfallin: isle
  • fitzgen: isle

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Copy link
Copy Markdown
Member

@cfallin cfallin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! These all look right to me; just one comment about a potential redundancy below. Happy to merge once that's resolved.

;; ireduce(xext(a) + xext(b)) --> a + b
(rule (simplify (ireduce ty (iadd cty (sextend cty x) (sextend cty y)))) (iadd ty x y))
(rule (simplify (ireduce ty (iadd cty (sextend cty x) (uextend cty y)))) (iadd ty x y))
(rule (simplify (ireduce ty (iadd cty (sextend cty y) (sextend cty x)))) (iadd ty x y))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this rule the same as the rule two lines up, with x and y swapped? In general I like that we're doing commutativity explicitly here but I think that in this case it's actually just a redundant match -- we'll match the same patterns again with renamed bindings, so the effect is that we'll always add two iadds to the egraph (which is not what we want).

Same pattern in the rest of this rule's variants I believe.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected the overlap checker to find true redundancies, do you know why it isn't in this case?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are in the mid-end so simplify is a multi-constructor (e-graphs!) -- we disable the overlap checker completely for this case.

I guess in theory a static check might still be possible but it would have to be something like: LHSes both fire and RHSes are exactly the same, which is much harder (need to see into external ctor semantics in the general case).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(The driver should dedup the same Value coming back twice though -- see here)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. I’ve fixed the duplicated rules.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the "redundancy" is somewhat confusing to me, and I think it'd better if we can clarify here.

3. Avoid overly general rewrites like commutativity and associativity. Instead,
prefer targeted instances of the rewrite (for example, canonicalizing adds
where one operand is a constant such that the constant is always the add's
second operand, rather than general commutativity for adds) or even writing
the "same" optimization rule multiple times.
For example, the commutativity in the first rule in the following snippet is
bad because it will match even when the first operand is not an add:
;; Commute to allow `(foo (add ...) x)`, when we see it, to match.
(foo x y) => (foo y x)
;; Optimize.
(foo x (add ...)) => (bar x)
Better is to commute only when we know that canonicalizing in this way will
all definitely allow the subsequent optimization rule to match:
;; Canonicalize all adds to `foo`'s second operand.
(foo (add ...) x) => (foo x (add ...))
;; Optimize.
(foo x (add ...)) => (bar x)
But even better in this case is to write the "same" optimization multiple
times:
(foo (add ...) x) => (bar x)
(foo x (add ...)) => (bar x)
The cost of rule-matching is amortized by the ISLE compiler, where as the
intermediate result of each rewrite allocates new e-nodes and requires
storage in the dataflow graph. Therefore, additional rules are cheaper than
additional e-nodes.
Commutativity and associativity in particular can cause huge amounts of
e-graph bloat.

The README says that commutative cases are better explicitly coded, not assumed by the compiler or overly generalized with other meta-rules. I see the redundant rules here are to exploit the commutativity, following the doc. Let me know if I'm missing something. Thanks!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bongjunj I think the issue here is that the left-hand sides are not even different commutative variants but literally the same (just alpha-renamed, i.e. with different binding spellings). With the right-hand sides the same, the effect of this is that matching with a particular x and y will produce both (iadd x y) and (iadd y x) as terms (so I was wrong above: this won't actually dedup -- and there's no reason to have both those forms produced when we don't have further information about x and y).

Said another way: what the README is describing is that we should have all commutative variants as left-hand sides explicitly in variations of a rule. But what the rules are doing here is not moving around pieces on the left-hand side, but just matching the same thing (always exactly equivalently) with different names.

I think "don't write the same left-hand side twice" is probably already implied by our rules but I'm happy to review a PR if you think it could be made more explicit!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, now I see what the rules are doing. Thanks for the detailed comment!!

@myunbin myunbin force-pushed the add-rules-040326 branch from 43e80e5 to f5b93d1 Compare April 6, 2026 01:52
Copy link
Copy Markdown
Member

@cfallin cfallin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@cfallin cfallin added this pull request to the merge queue Apr 6, 2026
Merged via the queue into bytecodealliance:main with commit a4fef42 Apr 6, 2026
79 checks passed
@myunbin myunbin deleted the add-rules-040326 branch April 7, 2026 00:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cranelift Issues related to the Cranelift code generator isle Related to the ISLE domain-specific language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants